#include <dm/os/db/db_pg.hpp>
#include <dm/string/string.hpp>
#include <dm/os/db/resultset_pg.hpp>
#include <dm/os/log/logger.hpp>

namespace dm{
namespace os{

static const char* logModule = "CDbPg.os.dm";

CDbPg::CDbPg( const char* dbName,const char* host,short port ):CDb(dbName,host,port){
	m_con = NULL;
}

CDbPg::~CDbPg(){
	if( m_con!=NULL )
		PQfinish(m_con);
}

CDb::EDbType CDbPg::dbType(){
	return DtPg;
}

bool CDbPg::isConnected(){
	if( m_con!=NULL ){
		switch(PQstatus(m_con)){
		case CONNECTION_OK:
			return true;

		case CONNECTION_STARTED:
			log().info(THISMODULE "等待进行连接");
			break;
		case CONNECTION_MADE:
			log().info(THISMODULE "连接成功，等待发送");
			break;
		case CONNECTION_AWAITING_RESPONSE:
			log().info(THISMODULE "等待来自服务器的响应");
			break;
		case CONNECTION_AUTH_OK:
			log().info(THISMODULE "已收到认证；等待后端启动结束");
			break;
		case CONNECTION_SSL_STARTUP:
			log().info(THISMODULE "协商SSL加密");
			break;
		case CONNECTION_SETENV:
			log().info(THISMODULE "协商环境驱动的参数设置");
			break;
		case CONNECTION_BAD:
			log().info(THISMODULE "链接故障");
			break;
		default:
			log().info(THISMODULE "未知原因");
		}
	}

	return false;
}

bool CDbPg::connect( const char* user,const char* pw ){
    if( m_con ){
    	log().debug(THISMODULE "释放连接");
        PQfinish(m_con);
    }

    if( m_port==-1 )
    	m_con = PQsetdbLogin(m_host.c_str(),NULL,NULL,NULL,m_dbName.c_str(),user,pw);
    else{
    	dm::string::CString port = dm::string::CString::fromInt16(m_port);
    	log().debug(THISMODULE "连接数据库:%s@%s:%s",m_dbName.c_str(),m_host.c_str(),port.c_str());
    	m_con = PQsetdbLogin(m_host.c_str(),port.c_str(),NULL,NULL,m_dbName.c_str(),user,pw);
    	if( m_con )
    		PQerrorMessage(m_con);
    	else{
    		log().error(THISMODULE "连接失败:%s:%s",m_host.c_str(),m_port);
    	}
    }
	return isConnected();
}

void CDbPg::disconnect( ){
    if( m_con ){
        PQfinish(m_con);
        m_con = NULL;
    }
}

bool CDbPg::exec( const char* sql ){
    if( isConnected() ){
        PGresult* result = PQexec(m_con,sql);
        if( result ){
            if( PQresultStatus(result)==PGRES_COMMAND_OK ){
                PQclear(result);
                return true;
            }
            PQclear(result);
        }
    }    

	return false;
}

dm::int64 CDbPg::execWithLastId( const char* sql ){
    if( isConnected() ){
    	char sql_x[2048];
    	std::sprintf(sql_x,"%s RETURNING ID");
        PGresult* result = PQexec(m_con,sql);
        if( result ){
            if( PQresultStatus(result)==PGRES_TUPLES_OK ){
            	dm::int64 rt = atol(PQgetvalue(result, 0, 0));
                PQclear(result);
                return rt;
            }
            PQclear(result);
        }
    }

	return -1;
}

CResultSet* CDbPg::query( const char* sql ){
	if( isConnected() ){
        CResultSetPg* rs = new CResultSetPg();

        rs->m_rst = PQexec(m_con,sql);
        if( rs->m_rst ){
            rs->m_r = -1;
            if( PQresultStatus(rs->m_rst)==PGRES_TUPLES_OK )
                return rs;
        }

        delete rs;
	}

	return NULL;
}

/**
 * 获取匹配字符串表名
 * @param pattern
 * @param rs
 * @return
 */
CResultSet* CDbPg::getTables( const char* pattern ){
	std::string sql = "select table_name from information_schema.tables where table_type='BASE TABLE' and table_name like '";
	sql += pattern;
	sql += "'";

	return query(sql.c_str());
}

}
}
